# -*- coding: utf-8 -*-
from odoo import http, _, tools
from odoo.http import request, HttpRequest, JsonRequest
import sys, os, jinja2, logging
import decimal, json, os, uuid, base64
from tornado.web import HTTPError
from reportbro import Report, ReportBroError
from datetime import datetime, timedelta

if hasattr(sys, 'frozen'):
    # When running on compiled windows binary, we don't have access to package loader.
    path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'demo'))
    loader = jinja2.FileSystemLoader(path)
else:
    loader = jinja2.PackageLoader('odoo.addons.odoo_report_bro', "demos")
jinja_env = jinja2.Environment('<%', '%>', '${', '}', loader=loader, autoescape=True)
_logger = logging.getLogger(__name__)
CLEAROLDREPORTRECORD = 5
path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'demos')) + '/FangSong.ttf'

song_font = {'value': '宋体', 'filename': path, 'bold_filename': path,
             'italic_filename': path, 'bold_italic_filename': path}
dispatch_old = HttpRequest.dispatch


def dispatch_new(self):
    """返回处理OPTION 请求，返回相对应的Header数据"""
    if request.httprequest.method == 'OPTIONS' and request.httprequest.path == '/reportbro/report/run' \
            and request.endpoint and request.endpoint.routing.get('cors'):
        headers = {
            'Access-Control-Allow-Headers':
                'Origin, X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Z-Key',
            'Access-Control-Allow-Methods': 'GET, PUT, OPTIONS',
            'Access-Control-Allow-Origin': '*',
        }
        return http.Response(status=200, headers=headers)
    return dispatch_old(self)


HttpRequest.dispatch = dispatch_new
_json_response_old = JsonRequest._json_response


def _json_response_new(self, result=None, error=None):
    """特殊的return 值"""
    if self.httprequest.path == '/reportbro/report/run' and result and self.httprequest.method == 'PUT':
        return http.Response(
            result, status=error and error.pop('http_status', 200) or 200,
            headers=[('Content-Type', 'txt/plain'), ('Content-Length', len(result))]
        )
    return _json_response_old(self, result, error)


JsonRequest._json_response = _json_response_new


# method to handle json encoding of datetime and Decimal
def jsonconverter(val):
    if isinstance(val, datetime):
        return '{date.year}-{date.month}-{date.day}'.format(date=val)
    if isinstance(val, decimal.Decimal):
        return str(val)


class ReportBroControllers(http.Controller):

    @http.route('/reportbro/design/<int:report_id>', type='http', auth='none', csrf=False, methods=['GET'])
    def get_demos(self, report_id, *args, **kwargs):
        """REPORTBRO 在Odoo中可以暂存pdf数据的demo"""
        template = jinja_env.get_template('base.html')
        report_data, header_name = request.env['report.bro'].get_all_report_data(report_id)
        return template.render({'report_data': report_data, 'report_id': report_id,
                                'header_name': header_name})

    @http.route('/reportbro/report/run', type='json', auth='user', cors='*', csrf=False, methods=['PUT', 'OPTIONS'])
    def reportbro_report_run_put(self, *args, **kwargs):
        """处理在Odoo中暂存数据"""
        json_data = json.loads(request.httprequest.data)
        return self.reportbro_report_run_put_method(json_data)

    @http.route('/reportbro/report/run', type='http', auth='user', cors='*', csrf=False, methods=['GET'])
    def reportbro_report_run_get(self, *args, **kwargs):
        """获取对应的Key在Odoo中的暂存数据，并删除对应的记录"""
        return self.reportbro_report_run_get_method()

    @http.route('/reportbro/report/save', type='http', auth='user', cors='*', csrf=False, methods=['POST'])
    def reportbro_report_save(self, *args, **kwargs):
        """获取对应的Key在Odoo中的暂存数据，并删除对应的记录"""
        return_val = request.env['report.bro'].report_bro_save_edit_val(request.httprequest.data)
        return request.make_response(json.dumps(return_val))

    def reportbro_report_run_put_method(self, json_data):
        """
        保存请求的的报表数据， 在数据中创建记录
        :return:
        """
        report_definition = json_data.get('report')
        output_format = json_data.get('outputFormat')
        if output_format not in ('pdf', 'xlsx'):
            raise HTTPError(400, reason='outputFormat parameter missing or invalid')
        data = json_data.get('data')
        is_test_data = bool(json_data.get('isTestData'))
        try:
            report = Report(report_definition, data, is_test_data, additional_fonts=[song_font])
        except Exception as e:
            raise HTTPError(400, reason='failed to initialize refport: ' + tools.ustr(e))
        if report.errors:
            _logger.error(tools.ustr(report.errors))
            return tools.ustr(report.errors)
        try:
            report_file = report.generate_pdf()
            key = str(uuid.uuid4())
            bro_obj = request.env['report.bro'].sudo()
            clear_old_record_date = (datetime.now() + timedelta(days=-1 * CLEAROLDREPORTRECORD)).strftime(
                "%Y-%m-%d %H:%M:%S")
            bro_rows = bro_obj.search([('create_date', '<', clear_old_record_date), ('is_test_data', '=', True)])
            bro_rows.unlink()
            bro_obj.create({
                'key': key,
                'report_definition': json.dumps(report_definition),
                'data': json.dumps(data, default=jsonconverter),
                'pdf_file': base64.b64encode(report_file),
                'pdf_file_size': len(report_file),
                'is_test_data': is_test_data,
            })
        except ReportBroError as err:
            _logger.error(tools.ustr(err))
            return tools.ustr(err)
        return 'key:%s' % key

    def reportbro_report_run_get_method(self):
        """
        获取数据库中可key 为请求key的记录取出 excel 报表数据并删除对应的记录（避免造成数据过多数据中数据过多）
        :return:
        """
        output_format = request.params.get('outputFormat')
        assert output_format in ('pdf', 'xlsx')
        key = request.params.get('key')
        report, report_file = None, None
        if key and len(key) == 36:
            row = request.env['report.bro'].sudo().search([('key', '=', key)], limit=1, order='create_date DESC')
            if not row:
                raise HTTPError(400,
                                reason='report not found (preview probably too old), update report preview and try again')
            if output_format == 'pdf' and row['pdf_file']:
                report_file = row['pdf_file']
            else:
                report_definition = json.loads(row['report_definition'])
                data = json.loads(row['data'])
                is_test_data = row['is_test_data']
                report = Report(report_definition, data, is_test_data, additional_fonts=[song_font])
                if report.errors:
                    raise HTTPError(400, reason='error generating report')
        else:

            json_data = json.loads(request.httprequest.data)
            report_definition = json_data.get('report')
            data = json_data.get('data')
            is_test_data = bool(json_data.get('isTestData'))
            if not isinstance(report_definition, dict) or not isinstance(data, dict):
                raise HTTPError(400, reason='report_definition or data missing')
            report = Report(report_definition, data, is_test_data, additional_fonts=[song_font])
            if report.errors:
                raise HTTPError(400, reason='error generating report')
        try:
            if output_format == 'pdf':
                if report_file is None:
                    report_file = report.generate_pdf()
                else:
                    report_file = base64.b64decode(report_file)
                headers = [('Content-Type', 'application/pdf'),
                           ('Content-Disposition', 'inline; filename="{filename}"'.format(
                               filename='report-' + str(datetime.now()) + '.pdf'))]
            else:
                report_file = report.generate_xlsx()
                headers = [('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'),
                           ('Content-Disposition', 'inline; filename="{filename}"'.format(
                               filename='report-' + str(datetime.now()) + '.xlsx'))
                           ]
            return request.make_response(report_file, headers=headers)
        except ReportBroError:
            raise HTTPError(400, reason='error generating report')
        return
